export = {}
/** 可索引类型接口能让我们规定: 用 字符串|数字 去索引某个对象得到的结果就一定为 某种类型 */
// 与使用接口描述函数类型差不多，我们也可以描述那些能够“通过索引得到”的类型，比如a[10]或ageMap["daniel"]。
// 可索引类型具有一个 索引签名，它描述了对象索引的类型，还有相应的索引返回值类型。 让我们看一个例子：
interface StringArray {
  [index: number/*← 多用户描述数组*/]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];
/* ↑
上面例子里，我们定义了StringArray接口，它具有索引签名。 这个索引签名表示了当用 number去索引StringArray时会得到string类型的返回值。 */




/** 如何同时使用数字索引和字符串索引？ */
/** 注意事项: */
// TypeScript支持两种索引签名：字符串和数字。 可以同时使用两种类型的索引
//
// ，但是数字索引的返回值必须是字符串索引返回值类型的子类型（subtype）。(容易误解的一点,这里说的子类型,虽然是"子",但其实它具有的属性要比父亲多)
//
// 这是因为当使用 number来索引时，JavaScript会将它尝试转换成string然后再去索引对象。
// 也就是说用 100（一个number）去索引等同于使用"100"（一个string）去索引，因此两者之间需要不矛盾。
/*
const obj = {
  123: "a",  // 这里定义一个数值类型的123这个属性
  "123": "b" // 这里在定义一个字符串类型的123这个属性，这里会报错：标识符“"123"”重复。 TS2300: Duplicate identifier '"123"'.
};
console.log(obj); // { '123': 'b' } 会发现第二个覆盖了第一个 说明的确将数字索引转换成了字符串索引
*/
//
// There are two types of supported index signatures: string and number. It is possible to support both types of indexers, but the type returned from a numeric indexer must be a subtype of the type returned from the string indexer. This is because when indexing with a number, JavaScript will actually convert that to a string before indexing into an object. That means that indexing with 100 (a number) is the same thing as indexing with "100" (a string), so the two need to be consistent.

class Animal { // ←父
  name: string;
}

class Dog extends Animal { //←子类型
  breed: string;
}

// 错误：使用数值型的字符串索引，有时会得到完全不同的Animal!
interface NotOkay {
  [x: number]: Animal/* ← 父,这样是不对的,应该和下面打个调 */; // TS2413: Numeric index type 'Animal' is not assignable to string index type 'Dog'.
  [x: string]: Dog/* ← 子 */;
}
/** 数字索引和字符串索引同时使用例子*/
interface X {
  [x: number]: {a:string,b:string};
  [x: string]: {a:string};
}
/** .1 源数据为字面量形式 */
// let x: X = {1: {a: 'a', b: 'b'}, 'hi': {a: 'yo'}};
/* ↑ 字面量形式无法正确使用
TS2322: Type '{ 1: { a: string; b: string; }; 'hi': { a: string; }; }' is not assignable to type 'X'.
Property '1' is incompatible with index signature.
Type '{ a: string; b: string; }' is not assignable to type '{ a: string; }'.
Object literal may only specify known properties, and 'b' does not exist in type '{ a: string; }'. */
/** .2 源数据为非字面量形式 */
// let xx = {1: {a: 'a'}, 'hi': {a: 'yo'}}; // Property 'b' is missing in type '{ a: string; }' but required in type '{ a: string; b: string; }'.
// let xx = {1: {a: 'a',b:'b'}, 'hi': {a: 'yo'}}; // 数字索引的返回值a和b都包含才会验证通过
let xx = {1: {a: 'a',b:'b',c:'c'}, 'hi': {a: 'yo'}}; // 多写时可以的
let x: X = xx;

const obj = {
  123: "a", // 这里定义一个数值类型的123这个属性
  "123": "b" // 这里在定义一个字符串类型的123这个属性，这里会报错：标识符“"123"”重复。
};



/** 描述 dictionary设计模式(“dictionary” pattern)*/
/*
字符串索引签名能够很好的描述 dictionary设计模式(“dictionary” pattern)，并且它们也会确保所有属性与其返回值类型相匹配。

因为字符串索引声明了 obj.property和obj["property"]两种形式都可以。

下面的例子里， name的类型与字符串索引类型不匹配，所以类型检查器给出一个错误提示：
*/
interface NumberDictionary {
  [index: string]: number;
  length: number;    // 可以，length是number类型
  name: string       // 错误，`name`的类型与索引类型返回值的类型不匹配
}



/** 只读索引*/
//最后，你可以将索引签名设置为只读，这样就防止了给索引赋值：
interface ReadonlyStringArray {
  readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"]; // TS2451: Cannot redeclare block-scoped variable 'myArray'.
myArray[2] = "Mallory"; // error!
